/* do not edit automatically generated by mc from NameKey.  */
/* NameKey.mod provides a dynamic binary tree name to key.

Copyright (C) 2001-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#include <stddef.h>
#include <string.h>
#include <limits.h>
#   include "GStorage.h"
#   include "Gmcrts.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _NameKey_H
#define _NameKey_C

#   include "GSYSTEM.h"
#   include "GStorage.h"
#   include "GIndexing.h"
#   include "GStrIO.h"
#   include "GStdIO.h"
#   include "GNumberIO.h"
#   include "GStrLib.h"
#   include "Glibc.h"
#   include "GASCII.h"
#   include "GM2RTS.h"

#   define NameKey_NulName 0
typedef unsigned int NameKey_Name;

typedef struct NameKey_Node_r NameKey_Node;

typedef char *NameKey_PtrToChar;

typedef NameKey_Node *NameKey_NameNode;

typedef enum {NameKey_less, NameKey_equal, NameKey_greater} NameKey_Comparison;

struct NameKey_Node_r {
                        NameKey_PtrToChar Data;
                        NameKey_Name Key;
                        NameKey_NameNode Left;
                        NameKey_NameNode Right;
                      };

static NameKey_NameNode BinaryTree;
static Indexing_Index KeyIndex;
static unsigned int LastIndice;

/*
   MakeKey - returns the Key of the symbol, a. If a is not in the
             name table then it is added, otherwise the Key of a is returned
             directly. Note that the name table has no scope - it merely
             presents a more convienient way of expressing strings. By a Key.
*/

extern "C" NameKey_Name NameKey_MakeKey (const char *a_, unsigned int _a_high);

/*
   makekey - returns the Key of the symbol, a. If a is not in the
             name table then it is added, otherwise the Key of a is returned
             directly. Note that the name table has no scope - it merely
             presents a more convienient way of expressing strings. By a Key.
             These keys last for the duration of compilation.
*/

extern "C" NameKey_Name NameKey_makekey (void * a);

/*
   GetKey - returns the name, a, of the key, Key.
*/

extern "C" void NameKey_GetKey (NameKey_Name key, char *a, unsigned int _a_high);

/*
   LengthKey - returns the StrLen of Key.
*/

extern "C" unsigned int NameKey_LengthKey (NameKey_Name Key);

/*
   IsKey - returns TRUE if string, a, is currently a key.
           We dont use the Compare function, we inline it and avoid
           converting, a, into a String, for speed.
*/

extern "C" unsigned int NameKey_IsKey (const char *a_, unsigned int _a_high);

/*
   KeyToCharStar - returns the C char * string equivalent for, key.
*/

extern "C" void NameKey_WriteKey (NameKey_Name key);

/*
   IsSameExcludingCase - returns TRUE if key1 and key2 are
                         the same. It is case insensitive.
                         This function deliberately inlines CAP for speed.
*/

extern "C" unsigned int NameKey_IsSameExcludingCase (NameKey_Name key1, NameKey_Name key2);

/*
   KeyToCharStar - returns the C char * string equivalent for, key.
*/

extern "C" void * NameKey_KeyToCharStar (NameKey_Name key);

/*
   CharKey - returns the key[i] character.
*/

extern "C" char NameKey_CharKey (NameKey_Name key, unsigned int i);

/*
   DoMakeKey - finds the name, n, in the tree or else create a name.
               If a name is found then the string, n, is deallocated.
*/

static NameKey_Name DoMakeKey (NameKey_PtrToChar n, unsigned int higha);

/*
   Compare - return the result of Names[i] with Names[j]
*/

static NameKey_Comparison Compare (NameKey_PtrToChar pi, NameKey_Name j);

/*
   FindNodeAndParentInTree - search BinaryTree for a name.
                             If this name is found in the BinaryTree then
                             child is set to this name and father is set to the node above.
                             A comparison is returned to assist adding entries into this tree.
*/

static NameKey_Comparison FindNodeAndParentInTree (NameKey_PtrToChar n, NameKey_NameNode *child, NameKey_NameNode *father);


/*
   DoMakeKey - finds the name, n, in the tree or else create a name.
               If a name is found then the string, n, is deallocated.
*/

static NameKey_Name DoMakeKey (NameKey_PtrToChar n, unsigned int higha)
{
  NameKey_Comparison result;
  NameKey_NameNode father;
  NameKey_NameNode child;
  NameKey_Name k;

  result = FindNodeAndParentInTree (n, &child, &father);
  if (child == NULL)
    {
      if (result == NameKey_less)
        {
          Storage_ALLOCATE ((void **) &child, sizeof (NameKey_Node));
          father->Left = child;
        }
      else if (result == NameKey_greater)
        {
          /* avoid dangling else.  */
          Storage_ALLOCATE ((void **) &child, sizeof (NameKey_Node));
          father->Right = child;
        }
      child->Right = NULL;
      child->Left = NULL;
      LastIndice += 1;
      child->Key = LastIndice;
      child->Data = n;
      Indexing_PutIndice (KeyIndex, child->Key, reinterpret_cast<void *> (n));
      k = LastIndice;
    }
  else
    {
      Storage_DEALLOCATE (reinterpret_cast<void **> (&n), higha+1);
      k = child->Key;
    }
  return k;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   Compare - return the result of Names[i] with Names[j]
*/

static NameKey_Comparison Compare (NameKey_PtrToChar pi, NameKey_Name j)
{
  NameKey_PtrToChar pj;
  char c1;
  char c2;

  pj = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (j));
  c1 = (*pi);
  c2 = (*pj);
  while ((c1 != ASCII_nul) || (c2 != ASCII_nul))
    {
      if (c1 < c2)
        {
          return NameKey_less;
        }
      else if (c1 > c2)
        {
          /* avoid dangling else.  */
          return NameKey_greater;
        }
      else
        {
          /* avoid dangling else.  */
          pi += 1;
          pj += 1;
          c1 = (*pi);
          c2 = (*pj);
        }
    }
  return NameKey_equal;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FindNodeAndParentInTree - search BinaryTree for a name.
                             If this name is found in the BinaryTree then
                             child is set to this name and father is set to the node above.
                             A comparison is returned to assist adding entries into this tree.
*/

static NameKey_Comparison FindNodeAndParentInTree (NameKey_PtrToChar n, NameKey_NameNode *child, NameKey_NameNode *father)
{
  NameKey_Comparison result;

  /* firstly set up the initial values of child and father, using sentinal node  */
  (*father) = BinaryTree;
  (*child) = BinaryTree->Left;
  if ((*child) == NULL)
    {
      return NameKey_less;
    }
  else
    {
      do {
        result = Compare (n, (*child)->Key);
        if (result == NameKey_less)
          {
            (*father) = (*child);
            (*child) = (*child)->Left;
          }
        else if (result == NameKey_greater)
          {
            /* avoid dangling else.  */
            (*father) = (*child);
            (*child) = (*child)->Right;
          }
      } while (! (((*child) == NULL) || (result == NameKey_equal)));
      return result;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   MakeKey - returns the Key of the symbol, a. If a is not in the
             name table then it is added, otherwise the Key of a is returned
             directly. Note that the name table has no scope - it merely
             presents a more convienient way of expressing strings. By a Key.
*/

extern "C" NameKey_Name NameKey_MakeKey (const char *a_, unsigned int _a_high)
{
  NameKey_PtrToChar n;
  NameKey_PtrToChar p;
  unsigned int i;
  unsigned int higha;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  higha = StrLib_StrLen ((const char *) a, _a_high);
  Storage_ALLOCATE (reinterpret_cast<void **> (&p), higha+1);
  if (p == NULL)
    {
      M2RTS_HALT (-1);  /* out of memory error  */
      __builtin_unreachable ();
    }
  else
    {
      n = p;
      i = 0;
      while (i < higha)
        {
          (*p) = a[i];
          i += 1;
          p += 1;
        }
      (*p) = ASCII_nul;
      return DoMakeKey (n, higha);
    }
  ReturnException ("../../gcc-read-write/gcc/m2/gm2-compiler/NameKey.def", 20, 1);
  __builtin_unreachable ();
}


/*
   makekey - returns the Key of the symbol, a. If a is not in the
             name table then it is added, otherwise the Key of a is returned
             directly. Note that the name table has no scope - it merely
             presents a more convienient way of expressing strings. By a Key.
             These keys last for the duration of compilation.
*/

extern "C" NameKey_Name NameKey_makekey (void * a)
{
  NameKey_PtrToChar n;
  NameKey_PtrToChar p;
  NameKey_PtrToChar pa;
  unsigned int i;
  unsigned int higha;

  if (a == NULL)
    {
      return NameKey_NulName;
    }
  else
    {
      higha = static_cast<unsigned int> (libc_strlen (a));
      Storage_ALLOCATE (reinterpret_cast<void **> (&p), higha+1);
      if (p == NULL)
        {
          M2RTS_HALT (-1);  /* out of memory error  */
          __builtin_unreachable ();
        }
      else
        {
          n = p;
          pa = static_cast<NameKey_PtrToChar> (a);
          i = 0;
          while (i < higha)
            {
              (*p) = (*pa);
              i += 1;
              p += 1;
              pa += 1;
            }
          (*p) = ASCII_nul;
          return DoMakeKey (n, higha);
        }
    }
  ReturnException ("../../gcc-read-write/gcc/m2/gm2-compiler/NameKey.def", 20, 1);
  __builtin_unreachable ();
}


/*
   GetKey - returns the name, a, of the key, Key.
*/

extern "C" void NameKey_GetKey (NameKey_Name key, char *a, unsigned int _a_high)
{
  NameKey_PtrToChar p;
  unsigned int i;
  unsigned int higha;

  p = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (key));
  i = 0;
  higha = _a_high;
  while (((p != NULL) && (i <= higha)) && ((*p) != ASCII_nul))
    {
      a[i] = (*p);
      p += 1;
      i += 1;
    }
  if (i <= higha)
    {
      a[i] = ASCII_nul;
    }
}


/*
   LengthKey - returns the StrLen of Key.
*/

extern "C" unsigned int NameKey_LengthKey (NameKey_Name Key)
{
  unsigned int i;
  NameKey_PtrToChar p;

  p = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (Key));
  i = 0;
  while ((*p) != ASCII_nul)
    {
      i += 1;
      p += 1;
    }
  return i;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   IsKey - returns TRUE if string, a, is currently a key.
           We dont use the Compare function, we inline it and avoid
           converting, a, into a String, for speed.
*/

extern "C" unsigned int NameKey_IsKey (const char *a_, unsigned int _a_high)
{
  NameKey_NameNode child;
  NameKey_PtrToChar p;
  unsigned int i;
  unsigned int higha;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  /* firstly set up the initial values of child, using sentinal node  */
  child = BinaryTree->Left;
  if (child != NULL)
    {
      do {
        i = 0;
        higha = _a_high;
        p = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (child->Key));
        while ((i <= higha) && (a[i] != ASCII_nul))
          {
            if (a[i] < (*p))
              {
                child = child->Left;
                i = higha;
              }
            else if (a[i] > (*p))
              {
                /* avoid dangling else.  */
                child = child->Right;
                i = higha;
              }
            else
              {
                /* avoid dangling else.  */
                if ((a[i] == ASCII_nul) || (i == higha))
                  {
                    /* avoid gcc warning by using compound statement even if not strictly necessary.  */
                    if ((*p) == ASCII_nul)
                      {
                        return TRUE;
                      }
                    else
                      {
                        child = child->Left;
                      }
                  }
                p += 1;
              }
            i += 1;
          }
      } while (! (child == NULL));
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   KeyToCharStar - returns the C char * string equivalent for, key.
*/

extern "C" void NameKey_WriteKey (NameKey_Name key)
{
  NameKey_PtrToChar s;

  s = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (key));
  while ((s != NULL) && ((*s) != ASCII_nul))
    {
      StdIO_Write ((*s));
      s += 1;
    }
}


/*
   IsSameExcludingCase - returns TRUE if key1 and key2 are
                         the same. It is case insensitive.
                         This function deliberately inlines CAP for speed.
*/

extern "C" unsigned int NameKey_IsSameExcludingCase (NameKey_Name key1, NameKey_Name key2)
{
  NameKey_PtrToChar pi;
  NameKey_PtrToChar pj;
  char c1;
  char c2;

  if (key1 == key2)
    {
      return TRUE;
    }
  else
    {
      pi = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (key1));
      pj = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (key2));
      c1 = (*pi);
      c2 = (*pj);
      while ((c1 != ASCII_nul) && (c2 != ASCII_nul))
        {
          if (((c1 == c2) || (((c1 >= 'A') && (c1 <= 'Z')) && (c2 == ((char) (( ((unsigned int) (c1))- ((unsigned int) ('A')))+ ((unsigned int) ('a'))))))) || (((c2 >= 'A') && (c2 <= 'Z')) && (c1 == ((char) (( ((unsigned int) (c2))- ((unsigned int) ('A')))+ ((unsigned int) ('a')))))))
            {
              pi += 1;
              pj += 1;
              c1 = (*pi);
              c2 = (*pj);
            }
          else
            {
              /* difference found  */
              return FALSE;
            }
        }
      return c1 == c2;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   KeyToCharStar - returns the C char * string equivalent for, key.
*/

extern "C" void * NameKey_KeyToCharStar (NameKey_Name key)
{
  if ((key == NameKey_NulName) || (! (Indexing_InBounds (KeyIndex, key))))
    {
      return NULL;
    }
  else
    {
      return Indexing_GetIndice (KeyIndex, key);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   CharKey - returns the key[i] character.
*/

extern "C" char NameKey_CharKey (NameKey_Name key, unsigned int i)
{
  NameKey_PtrToChar p;

  if (i >= (NameKey_LengthKey (key)))
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  p = static_cast<NameKey_PtrToChar> (NameKey_KeyToCharStar (key));
  p += i;
  return (*p);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void _M2_NameKey_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
  LastIndice = 0;
  KeyIndex = Indexing_InitIndex (1);
  Storage_ALLOCATE ((void **) &BinaryTree, sizeof (NameKey_Node));
  BinaryTree->Left = NULL;
}

extern "C" void _M2_NameKey_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
